package com.qijian.common.utils;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.resource.ResourceUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.mail.MailAccount;
import cn.hutool.extra.mail.MailUtil;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * 邮件信息处理类。
 *
 * @author supo
 */
public class EmailUtil extends MailUtil {

    public static MailAccount ACCOUNT;

    public static Map<String, String> templateMap = new HashMap<>();
    public static Map<String, String> templateHtmlMap = new HashMap<>();

    private final static String START_ROW = "${start_row}";
    private final static String END_ROW = "${end_row}";
    private final static String START_ROW_INDEX = "${start_row%s}";
    private final static String END_ROW_INDEX = "${end_row%s}";

    private final static String EMAIL_CHECK = "^([a-z0-9A-Z]+[-|\\.]?)+[a-z0-9A-Z]@([a-z0-9A-Z]+(-[a-z0-9A-Z]+)?\\.)+[a-zA-Z]{2,}$";

    static {
        ACCOUNT = new MailAccount();
        ACCOUNT.setHost("smtp.exmail.qq.com");
        ACCOUNT.setPort(465);
        ACCOUNT.setAuth(true);
        ACCOUNT.setSslEnable(true);
        ACCOUNT.setFrom("企简信息<qj@zjavim.com>");
        ACCOUNT.setPass("1Qaz.wsxss");
        System.setProperty("mail.mime.splitlongparameters", "false");

        templateMap.put("贷款信息", "您好，有一笔${0}的贷款将于${1}截止，本期应还款${2}元，请及时处理");
        templateMap.put("贷款信息-超期", "您好，有一笔${0}的贷款已于${1}截止，本期应还款${2}元，已超期请及时处理");
        templateMap.put("融资租赁", "您好，有一笔${0}的融资租赁将于${1}截止，本期应还款${2}元，请及时处理");
        templateMap.put("融资租赁-超期", "您好，有一笔${0}的融资租赁已于${1}截止，本期应还款${2}元，已超期请及时处理");
        templateMap.put("回款计划", "您好，有一笔${0}的回款将于${1}到期，剩余回款金额${2}元，请及时处理");
        templateMap.put("回款计划-超期", "您好，有一笔${0}的回款已超期，剩余回款金额${1}元，请及时处理");
        templateMap.put("PurchaseInquiry", "您好，有一单新的报价申请，请及时处理\n\t地址：${0}");

        templateHtmlMap.put("销售报价提醒", "emailTemplate/salesNotice.html");
        templateHtmlMap.put("销售报价财务提醒", "emailTemplate/salesNoticeFin.html");
        templateHtmlMap.put("竞价", "emailTemplate/offer.html");
        templateHtmlMap.put("竞价底特", "emailTemplate/offerDT.html");
        templateHtmlMap.put("竞价通知", "emailTemplate/offerStaff.html");
        templateHtmlMap.put("光伏竞价通知", "emailTemplate/offerStaffSfb.html");
        templateHtmlMap.put("中标", "emailTemplate/win.html");
        templateHtmlMap.put("外协中标", "emailTemplate/winOut.html");
        templateHtmlMap.put("光伏竞价", "emailTemplate/offerSfb.html");
        templateHtmlMap.put("光伏中标", "emailTemplate/winSfb.html");
        templateHtmlMap.put("光伏中标通知", "emailTemplate/winSfb1.html");
        templateHtmlMap.put("物流国内中标", "emailTemplate/winLogisticsInternal.html");
        templateHtmlMap.put("物流国际中标", "emailTemplate/winLogisticsInternational.html");
        templateHtmlMap.put("物流国内中标底特", "emailTemplate/winLogisticsInternalDT.html");
        templateHtmlMap.put("物流国际中标底特", "emailTemplate/winLogisticsInternationalDT.html");
        templateHtmlMap.put("物流竞价提醒", "emailTemplate/logisticsRemind.html");
        templateHtmlMap.put("外协竞价提醒", "emailTemplate/logisticsRemind.html");
        templateHtmlMap.put("核算工单通知", "emailTemplate/accountingNotice.html");

        templateHtmlMap.put("工装中标", "emailTemplate/winFixture.html");
        templateHtmlMap.put("工装竞价提醒", "emailTemplate/fixtureRemind.html");
        templateHtmlMap.put("工单及报检未完成提醒", "emailTemplate/orderInspection.html");

        templateHtmlMap.put("技术交底", "emailTemplate/quotationCraftNotice.html");

        templateHtmlMap.put("报关资料确认单", "emailTemplate/customsDeclaration.html");
        templateHtmlMap.put("开标提醒", "emailTemplate/purchaseNotice.html");
        templateHtmlMap.put("质量检验提醒", "emailTemplate/qualityNotice.html");
        templateHtmlMap.put("预算发行", "emailTemplate/budgetRelease.html");
        templateHtmlMap.put("BOM工艺未完成提醒", "emailTemplate/bomUnfinishedNotice.html");
        templateHtmlMap.put("请检单前道未完成提醒", "emailTemplate/qualityPreviousTicketNotFinishedNotice.html");
        templateHtmlMap.put("付款单提前付款提醒", "emailTemplate/accountPaidEarlyNotice.html");
        templateHtmlMap.put("采购竞价多价格中标", "emailTemplate/purchaseMultiplyBid.html");
        templateHtmlMap.put("销售合同数量和开工令列表数量提醒", "emailTemplate/salesProjectNotMatchNotice.html");
        templateHtmlMap.put("在制品成本异常", "emailTemplate/costException4Production.html");
        templateHtmlMap.put("开工令未绑定销售订单", "emailTemplate/projectUnbind.html");
        templateHtmlMap.put("开工令生产/物流延期", "emailTemplate/projectDelay.html");
        templateHtmlMap.put("流程未处理提醒", "emailTemplate/flowOverTime.html");
        templateHtmlMap.put("发货通知单未完成", "emailTemplate/shippingNotice.html");
        templateHtmlMap.put("发货通知单遗漏", "emailTemplate/deliveryRemind.html");
        templateHtmlMap.put("已发运但发货通知单未创建", "emailTemplate/deliveryRemind2.html");
        templateHtmlMap.put("BOM线路完成提醒质量", "emailTemplate/bomXLFinished.html");
        templateHtmlMap.put("零件工序未申请排版定额", "emailTemplate/ncWithoutPrice.html");
        templateHtmlMap.put("量具提醒", "emailTemplate/gaugeRemind.html");
        templateHtmlMap.put("每周量具提醒", "emailTemplate/gaugeRemindWeek.html");
        templateHtmlMap.put("量具过期提醒", "emailTemplate/gaugeExpiredRemind.html");

        templateHtmlMap.put("生产延期提醒", "emailTemplate/otdProductionReminder.html");
        templateHtmlMap.put("物流延期提醒", "emailTemplate/otdLogisticsReminder.html");
        templateHtmlMap.put("超出预算", "emailTemplate/budgetOver.html");
        templateHtmlMap.put("外协检验提醒", "emailTemplate/outInspectionRemind.html");
        templateHtmlMap.put("外协出库提醒", "emailTemplate/outOutboundRemind.html");
        templateHtmlMap.put("发货通知确认单", "emailTemplate/deliveryNotificationConfirmation.html");
        templateHtmlMap.put("转运单超时提醒", "emailTemplate/ncOrderTransport.html");
        templateHtmlMap.put("供应商复审超时提醒", "emailTemplate/purmSupplier.html");
        templateHtmlMap.put("转运单未接单提醒", "emailTemplate/orderTransportRemind.html");
        templateHtmlMap.put("商务交付日提醒", "emailTemplate/logisticsReminder.html");


        templateHtmlMap.put("发货计划通知", "emailTemplate/deliveryPlan.html");
        templateHtmlMap.put("开工令产品编码与销售订单的产品编码不一致", "emailTemplate/projectSalesCheck.html");
        templateHtmlMap.put("计划排产通知核算", "emailTemplate/productionPlanNotify.html");
        templateHtmlMap.put("商务确认延期回款日期延期提醒", "emailTemplate/otdRecordDelayNotice.html");

        templateHtmlMap.put("报价单-整单提交", "emailTemplate/quotationSubmitOrder.html");
        templateHtmlMap.put("请检单创建提醒", "emailTemplate/inspectionReportPlanCreateReminder.html");
        templateHtmlMap.put("外协报检到期预警", "emailTemplate/inspectionExpirationRemind.html");

        templateHtmlMap.put("车间工单未及时处理", "emailTemplate/mainProcessOrderRemind.html");
        templateHtmlMap.put("前道工序未完成异常", "emailTemplate/previousProcessUnFinished.html");
        templateHtmlMap.put("发货签收单待处理提醒", "emailTemplate/OutMaterialShipping.html");
        templateHtmlMap.put("合同评审超期提醒", "emailTemplate/quotationExtension.html");
        templateHtmlMap.put("合同评审录入提醒", "emailTemplate/quotationToDo.html");
        templateHtmlMap.put("开工令未绑bom提醒", "emailTemplate/projectUnBindingBom.html");
        templateHtmlMap.put("项目工艺文件缺失超期提醒", "emailTemplate/projectCraftFileNotice.html");

    }

    /**
     * 模版参数处理
     *
     * @param key    /
     * @param params /
     * @return /
     */
    public static String templateHandler(String key, List<Object> params) {
        String template = templateMap.get(key);
        if (template == null) {
            return null;
        }

        for (int i = 0; i < params.size(); i++) {
            template = template.replace("${" + i + "}", params.get(i).toString());
        }
        return template;
    }

    /**
     * 判断是否邮箱
     *
     * @param email /
     * @return /
     */
    public static boolean isEmail(String email) {
        if (StringUtils.isBlank(email)) {
            return false;
        }
        Pattern regex = Pattern.compile(EMAIL_CHECK);
        return regex.matcher(email).matches();
    }

    public static void sendEmail(String key, List<String> emailList, String subject, List<Object> params) {
        String html = readHtml(templateHtmlMap.get(key));
        String content = templateHandlers(html, params);
        EmailUtil.send(EmailUtil.ACCOUNT, emailList, subject, content, true);
    }

    public static void sendEmailMap(String key, List<String> emailList, String subject, Map<String, Object> params) {
        String html = readHtml(templateHtmlMap.get(key));
        String content = templateHandlers(html, params);
        EmailUtil.send(EmailUtil.ACCOUNT, emailList, subject, content, true);
    }

    public static void sendEmail(String key, List<String> emailList, String subject, List<Object> params, String... filePaths) {
        String html = readHtml(templateHtmlMap.get(key));
        String content = templateHandlers(html, params);
        if (filePaths != null && filePaths.length > 0) {
            File[] files = new File[filePaths.length];
            for (int i = 0; i < filePaths.length; i++) {
                files[i] = new File(filePaths[i]);
            }
            EmailUtil.send(EmailUtil.ACCOUNT, emailList, subject, content, true, files);
        } else {
            EmailUtil.send(EmailUtil.ACCOUNT, emailList, subject, content, true);
        }
    }

    public static void sendEmail(String key, List<String> emailList, String subject, List<Object> params, File... files) {
        String html = readHtml(templateHtmlMap.get(key));
        String content = templateHandlers(html, params);
        EmailUtil.send(EmailUtil.ACCOUNT, emailList, subject, content, true, files);
    }

    /**
     * 人员分开发邮件
     *
     * @param separateSend 是否分开发邮件
     * @param key
     * @param emailList
     * @param subject
     * @param params
     * @param files
     */
    public static void sendEmail(Boolean separateSend, String key, List<String> emailList, String subject, List<Object> params, File... files) {
        if (Objects.nonNull(separateSend) && Objects.equals(separateSend, true)) {
            String html = readHtml(templateHtmlMap.get(key));
            String content = templateHandlers(html, params);
            for (String email : emailList) {
                EmailUtil.send(EmailUtil.ACCOUNT, CollUtil.newArrayList(email), subject, content, true, files);
            }
        } else {
            sendEmail(key, emailList, subject, params, files);
        }
    }

    public static void sendEmailMap(String key, List<String> emailList, String subject, Map<String, Object> params, File... files) {
        String html = readHtml(templateHtmlMap.get(key));
        String content = templateHandlers(html, params);
        EmailUtil.send(EmailUtil.ACCOUNT, emailList, subject, content, true, files);
    }

    public static void sendEmailDetail(String key, List<String> emailList, String subject, List<Object> params, List<List<Object>> details) {
        String html = readHtml(templateHtmlMap.get(key));
        String content = templateHandlerDetails(html, params, details);
        EmailUtil.send(EmailUtil.ACCOUNT, emailList, subject, content, true);
    }

    public static void sendEmailDetail(String key, List<String> toList, List<String> cclList, String subject, List<Object> params, List<List<Object>> details, String... filePaths) {
        String html = readHtml(templateHtmlMap.get(key));
        String content = templateHandlerDetails(html, params, details);
        if (filePaths != null && filePaths.length > 0) {
            File[] files = new File[filePaths.length];
            for (int i = 0; i < filePaths.length; i++) {
                files[i] = new File(filePaths[i]);
            }
            EmailUtil.send(EmailUtil.ACCOUNT, toList, cclList, null, subject, content, true, files);
        } else {
            EmailUtil.send(EmailUtil.ACCOUNT, toList, cclList, null, subject, content, true);
        }
    }


    public static void sendEmailDetailAndFiles(String key, List<String> toList, List<String> cclList, String subject, List<Object> params, List<List<Object>> details, File... files) {
        String html = readHtml(templateHtmlMap.get(key));
        String content = templateHandlerDetails(html, params, details);
        EmailUtil.send(EmailUtil.ACCOUNT, toList, cclList, null, subject, content, true, files);
    }

    public static String readHtml(String filepath) {
        if (StrUtil.isBlank(filepath)) {
            return "";
        }
        StringBuilder htmlSb = new StringBuilder();
        BufferedReader br = null;
        try {
            br = ResourceUtil.getUtf8Reader(filepath);
            while (br.ready()) {
                htmlSb.append(br.readLine());
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (br != null) {
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return htmlSb.toString();
    }

    public static String templateHandlers(String template, List<Object> params) {
        if (template == null) {
            return null;
        }
        for (int i = 0; i < params.size(); i++) {
            if (params.get(i) instanceof BigDecimal) {
                template = template.replace("${" + i + "}", NumberUtils.decimalFormat(",##0.00", ((BigDecimal) params.get(i)).doubleValue()));
            } else {
                template = template.replace("${" + i + "}", params.get(i) == null ? "" : params.get(i).toString());
            }
        }
        return template;
    }

    public static String templateHandlers(String template, Map<String, Object> params) {
        if (template == null) {
            return null;
        }
        for (String key : params.keySet()) {
            Object value = params.get(key);
            if (value instanceof BigDecimal) {
                template = template.replace("${" + key + "}", NumberUtils.decimalFormat(",##0.00", ((BigDecimal) value).doubleValue()));
            } else {
                template = template.replace("${" + key + "}", value == null ? "" : value.toString());
            }
        }
        return template;
    }

    public static String templateHandlerDetails(String key, List<Object> params, List<List<Object>> details) {
        if (key == null) {
            return null;
        }
        if (params != null) {
            params = params.stream().map(p -> Objects.isNull(p) ? "" : p).collect(Collectors.toList());
            for (int i = 0; i < params.size(); i++) {
                Object obj = params.get(i);
                if (ObjectUtils.isNull(obj)) {
                    key = key.replace("${" + i + "}", StringUtils.EMPTY);
                } else {
                    key = key.replace("${" + i + "}", obj.toString());
                }
            }
        }

        int startIndex = key.indexOf(START_ROW);
        int endIndex = key.indexOf(END_ROW);
        if (startIndex > -1 && endIndex > -1) {
            StringBuilder rows = new StringBuilder();
            String oldKey = key.substring(startIndex, endIndex + END_ROW.length());
            String detailStr = key.substring(startIndex + START_ROW.length(), endIndex);
            if (StringUtils.isNotBlank(detailStr)) {
                for (int i = 0; i < details.size(); i++) {
                    String str = detailStr;
                    str = str.replace("${row0}", String.format("%s", (i + 1)));
                    for (int j = 0; j < details.get(i).size(); j++) {
                        if (details.get(i).get(j) instanceof BigDecimal) {
                            str = str.replace("${row" + (j + 1) + "}", NumberUtils.decimalFormat(",##0.000", ((BigDecimal) details.get(i).get(j)).doubleValue()));
                        } else {
                            if (ObjectUtils.isNotNull(details.get(i).get(j))) {
                                str = str.replace("${row" + (j + 1) + "}", details.get(i).get(j).toString());
                            } else {
                                str = str.replace("${row" + (j + 1) + "}", "");
                            }
                        }
                    }
                    rows.append(str);
                }
            }
            key = key.replace(oldKey, rows.toString());
        }
        return key;
    }

    /**
     * 覆盖多个detail循环插入数据
     *
     * @param key        html模板
     * @param params     基本参数
     * @param detailList 列表参数
     * @return 插入完数据的html
     */
    public static String templateHandlerMoreDetails(String key, List<Object> params, List<List<List<Object>>> detailList) {
        if (key == null) {
            return null;
        }
        if (params != null) {
            params = params.stream().map(p -> Objects.isNull(p) ? "" : p).collect(Collectors.toList());
            for (int i = 0; i < params.size(); i++) {
                Object obj = params.get(i);
                if (ObjectUtils.isNull(obj)) {
                    key = key.replace("${" + i + "}", StringUtils.EMPTY);
                } else {
                    key = key.replace("${" + i + "}", obj.toString());
                }
            }
        }
        for (int di = 0; di < detailList.size(); di++) {
            List<List<Object>> details = detailList.get(di);
            String tempStartTab = String.format(START_ROW_INDEX, (di == 0 ? "" : di));
            String tempEndTab = String.format(END_ROW_INDEX, (di == 0 ? "" : di));
            int startIndex = key.indexOf(tempStartTab);
            int endIndex = key.indexOf(tempEndTab);
            if (startIndex > -1 && endIndex > -1) {
                StringBuilder rows = new StringBuilder();
                String oldKey = key.substring(startIndex, endIndex + tempEndTab.length());
                String detailStr = key.substring(startIndex + tempStartTab.length(), endIndex);
                if (StringUtils.isNotBlank(detailStr)) {
                    for (int i = 0; i < details.size(); i++) {
                        String str = detailStr;
                        str = str.replace("${row0}", String.format("%s", (i + 1)));
                        for (int j = 0; j < details.get(i).size(); j++) {
                            if (details.get(i).get(j) instanceof BigDecimal) {
                                str = str.replace("${row" + (j + 1) + "}", NumberUtils.decimalFormat(",##0.000", ((BigDecimal) details.get(i).get(j)).doubleValue()));
                            } else {
                                if (ObjectUtils.isNotNull(details.get(i).get(j))) {
                                    str = str.replace("${row" + (j + 1) + "}", details.get(i).get(j).toString());
                                } else {
                                    str = str.replace("${row" + (j + 1) + "}", "");
                                }
                            }
                        }
                        rows.append(str);
                    }
                }
                key = key.replace(oldKey, rows.toString());
            }
        }
        return key;
    }
}
